﻿namespace Guia.Elements
{
    using System;
    using System.Windows.Automation;
    using Guia.Locator;
    using System.Diagnostics.Contracts;

    /// <summary>
    /// This class represents an abstract DataGrid-element.
    /// Attention: This class doesn't necessarily means a DataGrid of the WPF-Toolkit.
    /// Various elements are able to act as a Datagrid. For example, a ListView can contain a GridView; then it becomes a DataGrid. See the WPF-documentation for further information.
    /// </summary>
    public abstract class AbstractDataGrid : UiElement
    {
        /// <summary>
        /// Initializes a new instance of the AbstractDataGrid class. 
        /// </summary>
        /// <param name="automationElement">The AutomationElement representating the Grid.</param>
        protected AbstractDataGrid(AutomationElement automationElement)
            : base(automationElement)
        {
        }

        /// <summary>
        /// Gets the Header of this DataGrid.
        /// </summary>
        public DataGridHeader Header
        {
            get
            {
                return this.Get<DataGridHeader>(SearchCondition.FromAutomationCondition(Condition.TrueCondition));
            }
        }

        /// <summary>
        /// Gets the number of columns of this DataGrid.
        /// </summary>
        public int ColumnCount
        {
            get
            {
                return this.GetPattern<GridPattern>().Current.ColumnCount;
            }
        }

        /// <summary>
        /// Gets the number of rows of this DataGrid.
        /// </summary>
        public int RowCount
        {
            get
            {
                return this.GetPattern<GridPattern>().Current.RowCount;
            }
        }

        /// <summary>
        /// Gets a list of the avaiable rows.
        /// </summary>
        /// <typeparam name="T">The concrete type of the row.</typeparam>
        /// <returns>All typed rows.</returns>
        protected T[] GetRows<T>() where T : AbstractDataGridRow
        {
            return this.GetAll<T>();
        }

        /// <summary>
        /// Gets the cell with the given coordinates.
        /// </summary>
        /// <param name="row">The nr of the row, beginning at zero.</param>
        /// <param name="column">The nr of the column, beginning at zero.</param>
        /// <typeparam name="T">The type of the concrete DataGrid-cell (subclass of AbstractDataGridCell).</typeparam>
        /// <returns>An instance of DataGridCell.</returns>
        /// <exception cref="ArgumentOutOfRangeException">This exception is thrown if no cell exists at the given position.</exception>
        protected T GetCell<T>(int row, int column) where T : AbstractDataGridCell
        {
            Contract.Requires<ArgumentOutOfRangeException>(row >= 0);
            Contract.Requires<ArgumentOutOfRangeException>(column >= 0);
            AutomationElement cellElement = this.GetPattern<GridPattern>().GetItem(row, column);
            if (cellElement == null)
            {
                throw new ArgumentOutOfRangeException("No such cell in datagrid: column " + column + ", row " + row);
            }

            T element =
                (T)
                typeof(T).
                    GetConstructor(
                        new Type[] 
                        {
                            typeof(AutomationElement)
                        })
                    .Invoke(
                        new object[]
                        {
                            cellElement
                        });
            return element;
        }
    }
}
